package aidturith.ihm.panel.proto;

import java.awt.Rectangle;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.RowSorter.SortKey;
import javax.swing.SwingConstants;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;

import org.hibernate.Session;
import org.hibernate.Transaction;

import aidturith.Constant;
import aidturith.db.hibernate.HibernateUtil;
import aidturith.ihm.action.key.AlphabetAction;
import aidturith.ihm.action.key.DeleteAction;
import aidturith.ihm.action.key.DownAction;
import aidturith.ihm.action.key.EnterAction;
import aidturith.ihm.action.key.EscapeAction;
import aidturith.ihm.action.key.UpAction;
import aidturith.ihm.component.AutoCompleteTextField;
import aidturith.ihm.component.FilterTextField;

public abstract class TablePanel extends JPanel implements TableModelListener, ActionListener, ListSelectionListener {

	private static final long serialVersionUID = 1L;

	// Table
	private static String[] TABLE_HEADER;
	private JTable table;
	private DefaultTableModel model;
	private TableRowSorter<DefaultTableModel> sorter;
	private ArrayList<Object> selected_object;

	// Buttons
	private FilterTextField filter_jtf;
	private JButton edit_jb, add_jb, delete_jb;

	// boolean
	private boolean isEditing = false;
	private boolean isLocked = false;

	// Panels
	private JScrollPane scrollPane;
	private JPanel bottom_jp;

	// table functions
	public void clearSelection() {
		setSelected_object(null);
		table.clearSelection();
	}

	public void selectRow(int row) {
		if(row < 0) row = 0;
		if(row >= table.getRowCount()) row = table.getRowCount()-1;
		getTable().setRowSelectionInterval(row, row);

		if(selected_object == null)
			selected_object = new ArrayList<Object>();
		selected_object.removeAll(selected_object);
		for(int i = 0; i<getTABLE_HEADER().length; i++)
			selected_object.add(getModel().getValueAt(
					getTable().convertRowIndexToModel(row),
					getTable().convertColumnIndexToModel(i)));

		goToRow(row);
		if(Constant.DEBUG) System.out.println("select "+getSelected_object()+" "+getSelected_object().get(0).getClass());
	}

	public void goToRow(int row) {
		getTable().scrollRectToVisible(new Rectangle(getTable().getCellRect(row, 0, true)));
	}

	public int getVisibleRowCount() {
		return getSorter().getViewRowCount();
	}

	// interface
	public void switchToLabel(int column) {
		DefaultTableCellRenderer cellRenderer = new DefaultTableCellRenderer();
		cellRenderer.setHorizontalAlignment(SwingConstants.CENTER);
		getTable().getColumnModel().getColumn(column).setCellRenderer(cellRenderer);

		JTextField jTextField = new JTextField();
		jTextField.setHorizontalAlignment(SwingConstants.CENTER);

		KeyStroke escape = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
		jTextField.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(escape, "Escape");
		jTextField.getActionMap().put("Escape", new EscapeAction(this));

		getTable().getColumnModel().getColumn(column).setCellEditor(new DefaultCellEditor(jTextField));
	}

	public void switchToAutoComplete(int column, ArrayList<Object> list1) {
		DefaultTableCellRenderer cellRenderer = new DefaultTableCellRenderer();
		cellRenderer.setHorizontalAlignment(SwingConstants.CENTER);
		getTable().getColumnModel().getColumn(column).setCellRenderer(cellRenderer);

		AutoCompleteTextField tf = new AutoCompleteTextField(30, list1, false);
		tf.setHorizontalAlignment(SwingConstants.CENTER);
		getTable().getColumnModel().getColumn(column).setCellEditor(new DefaultCellEditor(tf));
	}

	public void mapShortcuts() {
		KeyStroke del = KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0);
		getTable().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(del, "Del");
		getTable().getActionMap().put("Del", new DeleteAction(this));

		KeyStroke enter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
		getTable().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(enter, "Enter");
		getTable().getActionMap().put("Enter", new EnterAction(this));

		KeyStroke escape = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
		getTable().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(escape, "Escape");
		getTable().getActionMap().put("Escape", new EscapeAction(this));

		for(int i=65; i<91; i++) {
			KeyStroke a = KeyStroke.getKeyStroke(i, 0);
			getTable().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(a, i);
			getTable().getActionMap().put(i, new AlphabetAction(this, (char) i));
		}

		KeyStroke up = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0);
		getTable().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(up, "Up");
		getTable().getActionMap().put("Up", new UpAction(this));

		KeyStroke down = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0);
		getTable().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(down, "Down");
		getTable().getActionMap().put("Down", new DownAction(this));
	}

	public abstract void initColumn(boolean lock);

	// database
	public void deleteRow() {
		int row = table.getSelectedRow();
		if(isEditing() && (getSelected_object() != null) && !(getSelected_object().get(0) instanceof String)) {
			Session session = HibernateUtil.getSession();
			try {
				Transaction tx = session.beginTransaction();
				session.delete(getSelected_object().get(0));
				tx.commit();
				if(Constant.DEBUG) System.out.println("delete "+getSelected_object());
			}
			finally {
				session.close();
			}
		}
		updateTableInfo();
		selectRow(row);
		getDelete_jb().setEnabled(true);
	}

	public abstract void addRow(String name);

	/**
	 * Met à jour les informations dans la JTable.
	 */
	public void updateTableInfo() {
		setLocked(true);
		List<? extends SortKey> keys = sorter.getSortKeys();
		getModel().setDataVector(populateModel(), getTABLE_HEADER());
		for(int i=0; i<getTABLE_HEADER().length; i++)
			switchToLabel(i);
		getSorter().setSortKeys(keys);
		getSorter().sort();
		initColumn(!isEditing);
		setLocked(false);
	}

	/**
	 * Va chercher les données dans la base pour peupler le modèle de la JTable.
	 * @return
	 */
	public abstract Object[][] populateModel();

	// listeners
	/**
	 * Déclanché quand une valeur dans la vue est changée, va répercuter le changement dans la base de donnée physique.
	 * @param e TableModelEvent
	 */
	@Override
	public abstract void tableChanged(TableModelEvent e);

	/**
	 * Selection listener.
	 */
	@Override
	public void valueChanged(ListSelectionEvent e) {
		if(e.getValueIsAdjusting()) {
			ListSelectionModel lsm = (ListSelectionModel) e.getSource();

			if(!lsm.isSelectionEmpty()) {
				int minIndex = lsm.getMinSelectionIndex();
				int maxIndex = lsm.getMaxSelectionIndex();
				for (int i = minIndex; i <= maxIndex; i++)
					if (lsm.isSelectedIndex(i)) {
						selectRow(i);
						if(isEditing) getDelete_jb().setEnabled(true);
						return;
					}
			} //else if(isEditing) getDelete_jb().setEnabled(false);
		}
	}

	// Getters & Setters
	public static String[] getTABLE_HEADER() { return TABLE_HEADER; }
	public static void setTABLE_HEADER(String[] tABLE_HEADER) { TABLE_HEADER = tABLE_HEADER; }

	public JTable getTable() { return table; }
	public void setTable(JTable table) { this.table = table; }

	public DefaultTableModel getModel() { return model; }
	public void setModel(DefaultTableModel model) { this.model = model; }

	public TableRowSorter<DefaultTableModel> getSorter() { return sorter; }
	public void setSorter(TableRowSorter<DefaultTableModel> sorter) { this.sorter = sorter; }

	public ArrayList<Object> getSelected_object() { return selected_object; }
	public void setSelected_object(ArrayList<Object> selected_object) { this.selected_object = selected_object; }

	public FilterTextField getFilter_jtf() { return filter_jtf; }
	public void setFilter_jtf(FilterTextField filter_jtf) { this.filter_jtf = filter_jtf; }

	public JButton getEdit_jb() { return edit_jb; }
	public void setEdit_jb(JButton edit_jb) { this.edit_jb = edit_jb; }

	public JButton getAdd_jb() { return add_jb; }
	public void setAdd_jb(JButton add_jb) { this.add_jb = add_jb; }

	public JButton getDelete_jb() { return delete_jb; }
	public void setDelete_jb(JButton delete_jb) { this.delete_jb = delete_jb; }

	public boolean isEditing() { return isEditing; }
	public void setEditing(boolean isEditing) { this.isEditing = isEditing; }

	public boolean isLocked() { return isLocked; }
	public void setLocked(boolean isLocked) { this.isLocked = isLocked; }

	public JScrollPane getScrollPane() { return scrollPane; }
	public void setScrollPane(JScrollPane scrollPane) { this.scrollPane = scrollPane; }

	public JPanel getBottom_jp() { return bottom_jp; }
	public void setBottom_jp(JPanel bottom_jp) { this.bottom_jp = bottom_jp; }

}
